from typing import Any, Dict, List, Optional, Union
from abc import ABC, abstractmethod
from pyassured.core.mysql_connection import MySQLUtil, MySQLConnectionPool


class BaseAssertionMixin:
    """通用断言方法混入类"""

    def equals(self, expected: Any) -> 'BaseAssertionMixin':
        """断言值等于期望值"""
        assert self._get_value() == expected, self._format_error_message("值不匹配", expected, self._get_value())
        return self

    def not_equals(self, unexpected: Any) -> 'BaseAssertionMixin':
        """断言值不等于指定值"""
        assert self._get_value() != unexpected, self._format_error_message("值不应该等于", unexpected)
        return self

    def is_not_none(self) -> 'BaseAssertionMixin':
        """断言值不为空"""
        assert self._get_value() is not None, self._format_error_message("不应该为 None")
        return self

    def contains(self, substring: str) -> 'BaseAssertionMixin':
        """断言字符串值包含指定子串"""
        value = self._get_value()
        assert isinstance(value, str), self._format_error_message("不是字符串类型")
        assert substring in value, self._format_error_message(f"不包含子串 '{substring}'")
        return self

    def greater_than(self, minimum: Union[int, float]) -> 'BaseAssertionMixin':
        """断言值大于指定值"""
        assert self._get_value() > minimum, self._format_error_message(f"应大于 {minimum}", actual=self._get_value())
        return self

    def less_than(self, maximum: Union[int, float]) -> 'BaseAssertionMixin':
        """断言值小于指定值"""
        assert self._get_value() < maximum, self._format_error_message(f"应小于 {maximum}", actual=self._get_value())
        return self

    def between(self, min_value: Union[int, float], max_value: Union[int, float]) -> 'BaseAssertionMixin':
        """断言值在指定范围内"""
        value = self._get_value()
        assert min_value <= value <= max_value, self._format_error_message(f"应在 {min_value}-{max_value} 之间",
                                                                           actual=value)
        return self

    @abstractmethod
    def _get_value(self) -> Any:
        """获取要断言的值"""
        pass

    @abstractmethod
    def _format_error_message(self, message: str, expected: Any = None, actual: Any = None) -> str:
        """格式化错误消息"""
        pass


class SQLExecutorMixin:
    """SQL执行混入类"""

    def _execute_sql(self, sql: str, params: Optional[tuple] = None, env: Optional[str] = None) -> Any:
        """执行SQL查询"""
        pool = MySQLConnectionPool()
        db = pool.get_connection(env=env)
        if params:
            formatted_sql = sql % params
        else:
            formatted_sql = sql
        return db, formatted_sql

    def _execute_sql_with_columns(self, sql: str, params: Optional[tuple] = None, env: Optional[str] = None) -> tuple:
        """执行SQL查询并返回结果和列名，使用连接池复用连接"""
        pool = MySQLConnectionPool()
        db = pool.get_connection(env=env)
        if params:
            formatted_sql = sql % params
        else:
            formatted_sql = sql

        try:
            with db.get_cursor() as cursor:
                cursor.execute(formatted_sql)
                result = cursor.fetchall()
                # 获取列名
                column_names = [desc[0] for desc in cursor.description] if cursor.description else []
                return result, column_names
        except Exception as e:
            raise e

    def _convert_tuple_to_dict(self, result: Any, column_names: List[str] = None) -> Any:
        """将元组结果转换为字典格式"""
        if isinstance(result, tuple):
            if column_names:
                return {column_names[i]: value for i, value in enumerate(result)}
            else:
                return {f"col_{i}": value for i, value in enumerate(result)}
        return result

    def _convert_tuples_to_dicts(self, results: List[Any], column_names: List[str] = None) -> List[Dict[str, Any]]:
        """将元组结果列表转换为字典格式列表"""
        if results and isinstance(results[0], tuple):
            if column_names:
                return [{column_names[i]: value for i, value in enumerate(row)} for row in results]
            else:
                return [{f"col_{i}": value for i, value in enumerate(row)} for row in results]
        return list(results) if results else []


class AssertionProcessor:
    """断言处理器，统一处理should断言逻辑"""

    ASSERTION_MAP = {
        'equals': 'equal',
        'equal': 'equal',
        'not_equals': 'not_equal',
        'not_equal': 'not_equal',
        'not_none': 'not_be_none',
        'not_be_none': 'not_be_none',
        'contains': 'contain',
        'contain': 'contain',
        'greater_than': 'be_greater_than',
        'be_greater_than': 'be_greater_than',
        'less_than': 'be_less_than',
        'be_less_than': 'be_less_than',
        'between': 'be_between'
    }

    @classmethod
    def process_assertion(cls, assertion_obj, assertion_type: str, expected_value=None):
        """处理断言调用"""
        method_name = cls.ASSERTION_MAP.get(assertion_type)
        if not method_name:
            raise ValueError(f"不支持的断言类型: {assertion_type}")

        method = getattr(assertion_obj, method_name)

        if assertion_type in ['not_none', 'not_be_none']:
            method()
        elif assertion_type == 'between':
            if not isinstance(expected_value, (list, tuple)) or len(expected_value) != 2:
                raise ValueError("between断言需要提供包含两个元素的列表或元组作为期望值")
            method(expected_value[0], expected_value[1])
        else:
            if expected_value is None:
                raise ValueError(f"断言类型 '{assertion_type}' 需要提供 expected_value")
            method(expected_value)

        return assertion_obj


class DatabaseAssertion(ABC, SQLExecutorMixin):
    """数据库断言基类"""

    def __init__(self, sql: str, params: Optional[tuple] = None, env: Optional[str] = None):
        """
        初始化数据库断言
        
        Args:
            sql: SQL查询语句
            params: SQL参数
            env: 指定环境，如果不指定则使用配置文件中的默认环境
        """
        self.sql = sql
        self.params = params or ()
        self.env = env

    @abstractmethod
    def execute(self) -> 'DatabaseAssertion':
        """执行断言"""
        pass


class SingleRecordAssertion(DatabaseAssertion):
    """单条记录字段断言"""

    def __init__(self, sql: str, params: Optional[tuple] = None, env: Optional[str] = None):
        super().__init__(sql, params, env)
        self.record = None

    def execute(self) -> 'SingleRecordAssertion':
        """执行查询并获取单条记录"""
        result, column_names = self._execute_sql_with_columns(self.sql, self.params, self.env)
        assert result and len(result) > 0, f"查询未返回任何记录: {self.sql}"

        self.record = self._convert_tuple_to_dict(result[0], column_names)
        return self

    def field(self, field_name: str) -> 'FieldAssertion':
        """获取字段断言对象"""
        assert self.record is not None, "请先执行 execute() 方法"
        field_value = self.record.get(field_name)
        return FieldAssertion(field_name, field_value)


class MultipleRecordsAssertion(DatabaseAssertion):
    """多条记录数量断言"""

    def __init__(self, sql: str, params: Optional[tuple] = None, env: Optional[str] = None):
        super().__init__(sql, params, env)
        self.records = None

    def execute(self) -> 'MultipleRecordsAssertion':
        """执行查询并获取多条记录"""
        result, column_names = self._execute_sql_with_columns(self.sql, self.params, self.env)

        self.records = self._convert_tuples_to_dicts(result, column_names)
        return self

    def count(self) -> 'CountAssertion':
        """获取记录数量断言对象"""
        assert self.records is not None, "请先执行 execute() 方法"
        return CountAssertion(len(self.records))

    def all_records(self) -> 'BatchRecordsAssertion':
        """获取批量记录断言对象"""
        assert self.records is not None, "请先执行 execute() 方法"
        return BatchRecordsAssertion(self.records)


class BatchRecordsAssertion:
    """批量记录验证"""

    def __init__(self, records: List[Dict[str, Any]]):
        self.records = records

    def all_have_field(self, field_name: str, expected_value: Any = None) -> 'BatchRecordsAssertion':
        """验证所有记录都包含指定字段，可选验证字段值"""
        for i, record in enumerate(self.records):
            assert field_name in record, f"第 {i + 1} 条记录缺少字段 '{field_name}'"
            if expected_value is not None:
                actual_value = record[field_name]
                assert actual_value == expected_value, f"第 {i + 1} 条记录字段 '{field_name}' 值不匹配，期望: {expected_value}, 实际: {actual_value}"
        return self

    def none_have_field(self, field_name: str, forbidden_value: Any) -> 'BatchRecordsAssertion':
        """验证所有记录的指定字段都不等于禁止值"""
        for i, record in enumerate(self.records):
            if field_name in record:
                actual_value = record[field_name]
                assert actual_value != forbidden_value, f"第 {i + 1} 条记录字段 '{field_name}' 包含禁止值: {forbidden_value}"
        return self


class FieldAssertion(BaseAssertionMixin):
    """字段断言"""

    def __init__(self, field_name: str, field_value: Any):
        self.field_name = field_name
        self.field_value = field_value

    def should(self, assertion_type: str = None, expected_value=None):
        """返回should断言对象或执行参数化断言
        
        Args:
            assertion_type (str, optional): 断言类型，如果提供则直接执行断言
            expected_value: 期望值（某些断言类型不需要）
            
        Returns:
            FieldAssertionShould: 如果没有提供assertion_type，返回should断言对象
            FieldAssertion: 如果提供了assertion_type，执行断言后返回自身
        """
        if assertion_type is None:
            return FieldAssertionShould(self.field_name, self.field_value)
        else:
            # 使用AssertionProcessor处理参数化断言
            should_obj = FieldAssertionShould(self.field_name, self.field_value)
            AssertionProcessor.process_assertion(should_obj, assertion_type, expected_value)
            return self

    def _get_value(self) -> Any:
        """获取要断言的值"""
        return self.field_value

    def _format_error_message(self, message: str, expected: Any = None, actual: Any = None) -> str:
        """格式化错误消息"""
        if expected is not None and actual is not None:
            return f"字段 '{self.field_name}' {message}，期望: {expected}, 实际: {actual}"
        elif expected is not None:
            return f"字段 '{self.field_name}' {message}: {expected}"
        else:
            return f"字段 '{self.field_name}' {message}"


class CountAssertion(BaseAssertionMixin):
    """数量断言"""

    def __init__(self, actual_count: int):
        self.actual_count = actual_count

    def should(self, assertion_type: str = None, expected_value=None):
        """返回should断言对象或执行参数化断言
        
        Args:
            assertion_type (str, optional): 断言类型，如果提供则直接执行断言
            expected_value: 期望值（某些断言类型不需要）
            
        Returns:
            CountAssertionShould: 如果没有提供assertion_type，返回should断言对象
            CountAssertion: 如果提供了assertion_type，执行断言后返回自身
        """
        if assertion_type is None:
            return CountAssertionShould(self.actual_count)
        else:
            # 使用AssertionProcessor处理参数化断言
            should_obj = CountAssertionShould(self.actual_count)
            AssertionProcessor.process_assertion(should_obj, assertion_type, expected_value)
            return self

    def _get_value(self) -> Any:
        """获取要断言的值"""
        return self.actual_count

    def _format_error_message(self, message: str, expected: Any = None, actual: Any = None) -> str:
        """格式化错误消息"""
        if expected is not None and actual is not None:
            return f"记录数量{message}，期望: {expected}, 实际: {actual}"
        elif expected is not None:
            return f"记录数量{message}: {expected}"
        else:
            return f"记录数量{message}，实际: {self.actual_count}"


class FieldAssertionShould(BaseAssertionMixin):
    """字段断言Should类，提供流畅的断言语法"""

    def __init__(self, field_name: str, field_value: Any):
        self.field_name = field_name
        self.field_value = field_value

    def __call__(self, assertion_type: str, expected_value=None):
        """执行断言
        
        Args:
            assertion_type (str): 断言类型
            expected_value: 期望值（某些断言类型不需要）
            
        Returns:
            FieldAssertionShould: 返回自身以支持链式调用
        """
        return AssertionProcessor.process_assertion(self, assertion_type, expected_value)

    def _get_value(self) -> Any:
        """获取要断言的值"""
        return self.field_value

    def _format_error_message(self, message: str, expected: Any = None, actual: Any = None) -> str:
        """格式化错误消息"""
        if expected is not None and actual is not None:
            return f"字段 '{self.field_name}' {message}，期望: {expected}, 实际: {actual}"
        elif expected is not None:
            return f"字段 '{self.field_name}' {message}: {expected}"
        else:
            return f"字段 '{self.field_name}' {message}"

    # 为了保持向后兼容性，保留原有的方法名
    def equal(self, expected: Any) -> 'FieldAssertionShould':
        """断言字段值应该等于期望值"""
        return self.equals(expected)

    def not_equal(self, unexpected: Any) -> 'FieldAssertionShould':
        """断言字段值应该不等于指定值"""
        return self.not_equals(unexpected)

    def not_be_none(self) -> 'FieldAssertionShould':
        """断言字段值应该不为空"""
        return self.is_not_none()

    def contain(self, substring: str) -> 'FieldAssertionShould':
        """断言字段值应该包含指定子串"""
        return self.contains(substring)

    def be_greater_than(self, minimum: Union[int, float]) -> 'FieldAssertionShould':
        """断言字段值应该大于指定值"""
        return self.greater_than(minimum)

    def be_less_than(self, maximum: Union[int, float]) -> 'FieldAssertionShould':
        """断言字段值应该小于指定值"""
        return self.less_than(maximum)

    def be_between(self, min_value: Union[int, float], max_value: Union[int, float]) -> 'FieldAssertionShould':
        """断言字段值应该在指定范围内"""
        return self.between(min_value, max_value)


class CountAssertionShould(BaseAssertionMixin):
    """数量断言Should类，提供流畅的断言语法"""

    def __init__(self, actual_count: int):
        self.actual_count = actual_count

    def __call__(self, assertion_type: str, expected_value=None):
        """执行断言
        
        Args:
            assertion_type (str): 断言类型
            expected_value: 期望值（某些断言类型不需要）
            
        Returns:
            CountAssertionShould: 返回自身以支持链式调用
        """
        return AssertionProcessor.process_assertion(self, assertion_type, expected_value)

    def _get_value(self) -> Any:
        """获取要断言的值"""
        return self.actual_count

    def _format_error_message(self, message: str, expected: Any = None, actual: Any = None) -> str:
        """格式化错误消息"""
        if expected is not None and actual is not None:
            return f"记录数量{message}，期望: {expected}, 实际: {actual}"
        elif expected is not None:
            return f"记录数量{message}: {expected}"
        else:
            return f"记录数量{message}，实际: {self.actual_count}"

    # 为了保持向后兼容性，保留原有的方法名
    def equal(self, expected: int) -> 'CountAssertionShould':
        """断言数量应该等于期望值"""
        return self.equals(expected)

    def not_equal(self, unexpected: int) -> 'CountAssertionShould':
        """断言数量应该不等于指定值"""
        return self.not_equals(unexpected)

    def be_greater_than(self, minimum: int) -> 'CountAssertionShould':
        """断言数量应该大于指定值"""
        return self.greater_than(minimum)

    def be_less_than(self, maximum: int) -> 'CountAssertionShould':
        """断言数量应该小于指定值"""
        return self.less_than(maximum)

    def be_between(self, min_count: int, max_count: int) -> 'CountAssertionShould':
        """断言数量应该在指定范围内"""
        return self.between(min_count, max_count)


# 便捷函数
def assert_single_record(sql: str, params: Optional[tuple] = None, env: Optional[str] = None) -> SingleRecordAssertion:
    """创建单条记录断言
    
    Args:
        sql: SQL查询语句
        params: SQL参数
        env: 指定环境，如果不指定则使用配置文件中的默认环境
    """
    return SingleRecordAssertion(sql, params, env)


def assert_multiple_records(sql: str, params: Optional[tuple] = None,
                            env: Optional[str] = None) -> MultipleRecordsAssertion:
    """创建多条记录断言
    
    Args:
        sql: SQL查询语句
        params: SQL参数
        env: 指定环境，如果不指定则使用配置文件中的默认环境
    """
    return MultipleRecordsAssertion(sql, params, env)
